package cn.tedu.straw.api.question.service.impl;

import cn.tedu.straw.api.question.dto.PostQuestionDTO;
import cn.tedu.straw.api.question.dto.PostQuestionMessage;
import cn.tedu.straw.api.question.ex.InsertException;
import cn.tedu.straw.api.question.ex.QuestionNotFoundException;
import cn.tedu.straw.api.question.mapper.QuestionMapper;
import cn.tedu.straw.api.question.mapper.QuestionTagMapper;
import cn.tedu.straw.api.question.mapper.UserQuestionMapper;
import cn.tedu.straw.api.question.service.IQuestionService;
import cn.tedu.straw.api.question.vo.QuestionDetailVO;
import cn.tedu.straw.api.question.vo.QuestionListItemVO;
import cn.tedu.straw.api.question.vo.QuestionSimpleVO;
import cn.tedu.straw.commons.model.Question;
import cn.tedu.straw.commons.model.QuestionTag;
import cn.tedu.straw.commons.model.UserQuestion;
import cn.tedu.straw.commons.vo.TagVO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author tedu.cn
 * @since 2020-11-11
 */
@Service
@Slf4j
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements IQuestionService {

    @Autowired
    QuestionMapper questionMapper;
    @Autowired
    QuestionTagMapper questionTagMapper;
    @Autowired
    UserQuestionMapper userQuestionMapper;
    @Autowired
    Gson gson;

    @KafkaListener
    public void receivePostQuestion(ConsumerRecord<String, String> record){
        //接收收到消息的值，也就是发送消息时的第二个参数
        String data = record.value();
        //将接收数据还原为对象
        PostQuestionMessage message=gson.fromJson(data,PostQuestionMessage.class);
        //再调用原本业务方法来发布问题
        post(message.getPostQuestionDTO(),message.getUserId(),message.getUserNickName());

    }
    @Transactional
    @Override
    public void post(PostQuestionDTO postQuestionDTO, Integer userId, String userNickName) {
        // 创建当前时间对象now
        LocalDateTime now = LocalDateTime.now();
        // 创建Question对象
        Question question = new Question();
        // 向Question对象中补全数据：title < 参数title
        question.setTitle(postQuestionDTO.getTitle());
        // 向Question对象中补全数据：content < 参数content
        question.setContent(postQuestionDTO.getContent());
        // 向Question对象中补全数据：userId < 参数userId
        question.setUserId(userId);
        // 向Question对象中补全数据：userNickName < 参数userNickName
        question.setUserNickName(userNickName);
        // 向Question对象中补全数据：status < 0
        question.setStatus(0);
        // 向Question对象中补全数据：hits < 0
        question.setHits(0);
        // 向Question对象中补全数据：tagIds < Arrays.toString(参数tagIds)
        question.setTagIds(Arrays.toString(postQuestionDTO.getTagIds()));
        // 向Question对象中补全数据：2个时间 < now
        question.setGmtCreate(now);
        question.setGmtModified(now);
        // 基于Question对象调用questionMapper.insert()方法插入“问题”数据，并获取返回的受影响行数
        int rows = questionMapper.insert(question);
        // 判断返回值是否不为1
        if (rows != 1) {
            // 是：抛出InsertException
            throw new InsertException("发表问题失败！服务器忙，请稍后再次尝试！");
        }

        // 遍历参数tagIds
        for (Integer tagId : postQuestionDTO.getTagIds()) {
            // 创建QuestionTag对象
            QuestionTag questionTag = new QuestionTag();
            // 向QuestionTag对象中补全数据：questionId < question.getId()
            questionTag.setQuestionId(question.getId());
            // 向QuestionTag对象中补全数据：tagId < 被遍历的元素
            questionTag.setTagId(tagId);
            // 向QuestionTag对象中补全数据：2个时间 < now
            questionTag.setGmtCreate(now);
            questionTag.setGmtModified(now);
            // 基于QuestionTag对象调用questionTagMapper.insert()方法向question_tag表中插入数据，并获取返回值
            rows = questionTagMapper.insert(questionTag);
            // 判断返回值是否不为1
            if (rows != 1) {
                // 是：抛出InsertException
                throw new InsertException("发表问题失败！服务器忙，请稍后再次尝试！");
            }
        }

        // 遍历参数teacherIds
        for (Integer teacherId : postQuestionDTO.getTeacherIds()) {
            // 创建UserQuestion对象
            UserQuestion userQuestion = new UserQuestion();
            // 向UserQuestion对象中补全数据：questionId < question.getId()
            userQuestion.setQuestionId(question.getId());
            // 向UserQuestion对象中补全数据：userId < 被遍历的元素
            userQuestion.setUserId(teacherId);
            // 向UserQuestion对象中补全数据：2个时间 < now
            userQuestion.setGmtCreate(now);
            userQuestion.setGmtModified(now);
            // 基于UserQuestion对象调用userQuestionMapper.insert()方法向user_question表中插入数据，并获取返回值
            rows = userQuestionMapper.insert(userQuestion);
            // 判断返回值是否不为1
            if (rows != 1) {
                // 是：抛出InsertException
                throw new InsertException("发表问题失败！服务器忙，请稍后再次尝试！");
            }
        }
    }

    @Override
    public QuestionDetailVO getDetail(Integer questionId) {
        QuestionDetailVO question = questionMapper.findDetailVOById(questionId);
        if (question == null) {
            throw new QuestionNotFoundException("获取问题的详情失败！尝试访问的数据不存在，可能已经被删除！");
        }
        return question;
    }

    @Override
    public List<QuestionSimpleVO> getMostHitsList() {
        return questionMapper.findMostHits();
    }

    @Value("${project.my-questions.page-size}")
    int pageSize;

    @Autowired
    RestTemplate restTemplate;
    @Override
    public PageInfo<QuestionListItemVO> getMyQuestions(Integer userId, Integer pageNum) {
        if (pageNum == null || pageNum < 1) {
            pageNum = 1;
        }
        PageHelper.startPage(pageNum, pageSize);
        List<QuestionListItemVO> questions = questionMapper.findByUserId(userId);
        //处理查询结果中的标签数据
        //遍历以上查询结果
        for (QuestionListItemVO question:questions
             ) {
            //得到每个问题在question表中记录的标签id,
            String tagIdsString = question.getTagIds();
            //去头，去尾，得到：2，3，15
            tagIdsString = tagIdsString.substring(1,tagIdsString.length()-1);
            //拆分成数组
            String[] tagsIdArray=tagIdsString.split(",");
            for (String tagId:tagsIdArray
                 ) {
                log.debug("tagId='{}'",tagId);
            }
            //准备当前问题的标签列表数据
            List<TagVO> tags=new ArrayList<>();
            for (String tagId:tagsIdArray
                 ) {
                // 远程服务调用的URL
                // -- 该URL不需要是网关转发的URL
                // -- 原本URL中应该是主机名（IP地址）和端口的位置，改为服务提供者在Eureka Server注册的名称
                // -- 原本URL中应该填写参数的部分，通过 {0}、{1} 这种格式的占位符来表示，其中的数字是从0开始顺序编号的
                String url="http://redis-tag/portal/tag/{0}";
                // 调用RestTemplate对象的getForObject()方法执行远程服务调用
                // 参数1--url：通过哪个URL执行远程服务调用
                // 参数2--responseType：通过远程服务调用得到的数据的类型
                // 参数3--uriVariables：可变参数，是URL中 {0} 这些占位符对应的值
                TagVO tag=restTemplate.getForObject(url,TagVO.class,tagId);
                // 将得到的标签数据添加到集合中
                tags.add(tag);
            }
            // 循环完成后，集合中已经包含当前“问题”的所有标签数据，设置到“问题”中
            question.setTags(tags);
        }
        PageInfo<QuestionListItemVO> pageInfo = new PageInfo<>(questions);
        return pageInfo;
    }

}
